import json

import xlrd
import xlwt
from django.core.paginator import EmptyPage, Paginator
from django.core.cache import cache
from django.http import HttpResponse, JsonResponse
from legacy import BytesIO

from . import my_util
from .exception import BizError, StatusCode
from .models import Account, Teacher, Student, Score, Class, Lesson
from .response import ApiResponse


# Create your views here.
# 帐号相关接口
def login(request):
    json_param = json.loads(request.body)
    username = json_param.get('username', '')
    pwd = json_param.get('pwd', '')

    if len(username) <= 0 or len(pwd) <= 0:
        raise BizError(StatusCode.USER_PWD_ERR)

    try:
        user_account = Account.objects.values('a_id', 't_id', 'username',
                                              'pwd', 'pwd_salt', 'level').get(username=username)
    except:
        raise BizError(StatusCode.USER_PWD_ERR)
    else:
        flag = my_util.check_pwd(pwd, user_account['pwd_salt'], user_account['pwd'])
        if not flag:
            raise BizError(StatusCode.USER_PWD_ERR)
        if user_account['username'] != 'admin':
            try:
                teacher = Teacher.objects.get(t_id=user_account['t_id'])
            except:
                raise BizError(StatusCode.USER_PWD_ERR)
            else:
                user_account['name'] = teacher.t_name

        auth_token = my_util.get_auth_token(str(user_account['a_id']))
        user_account['auth_token'] = auth_token
        del user_account['pwd']
        del user_account['pwd_salt']
        cache.set(auth_token, user_account, timeout=None)

        return ApiResponse(user_account)


def generate_account(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    t_id = json_param.get('t_id', '')

    if t_id == '':
        raise BizError(StatusCode.NOT_PARAM)

    try:
        Teacher.objects.get(t_id=t_id)
    except:
        raise BizError(StatusCode.NOT_TEACHER)

    username = my_util.get_username(8)
    while True:
        try:
            Account.objects.get(username=username)
        except:
            break
        else:
            username = my_util.get_username(8)

    pwd = my_util.get_pwd_salt(8)
    pwd_salt = my_util.get_pwd_salt(6)

    new_account = Account(t_id=t_id, username=username, pwd=my_util.get_md5(pwd + pwd_salt),
                          pwd_salt=pwd_salt, level='1')

    try:
        new_account.save()
    except:
        raise BizError(StatusCode.TEACHER_ACCOUNT_EXIST)
    else:
        return ApiResponse({"username": username, "pwd": pwd})


def edit_pwd(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    t_id = json_param.get('t_id', '')
    pwd = json_param.get('pwd', '')

    if t_id == '' or pwd == '':
        raise BizError(StatusCode.NOT_PARAM)

    try:
        record = Account.objects.get(t_id=t_id)
    except:
        raise BizError(StatusCode.NOT_TEACHER_ACCOUNT)
    else:
        pwd_salt = my_util.get_pwd_salt(6)
        record.pwd = my_util.get_md5(pwd + pwd_salt)
        record.pwd_salt = pwd_salt
        record.save()

    return ApiResponse({})


def list_account(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    page_no = json_param.get('page_no', 1)
    page_size = json_param.get('page_size', 10)

    record_list = Account.objects.all().values().order_by('a_id')
    paginator = Paginator(record_list, page_size)
    for i in range(len(record_list)):
        try:
            teacher = Teacher.objects.values().get(t_id=record_list[i]['t_id'])
        except:
            record_list[i]['t_name'] = ""
        else:
            record_list[i]['t_name'] = teacher['t_name']

    try:
        records = [c for c in paginator.page(page_no)]
    except EmptyPage:
        records = []

    data = {
        'list': records,
        'total_page': paginator.num_pages,
        'page_no': page_no,
        'page_size': page_size
    }
    return ApiResponse(data)


def logout(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')

    cache.delete(auth_token)

    return ApiResponse({})


def del_account(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    a_id = json_param.get('a_id', '')

    try:
        record = Account.objects.get(a_id=a_id)
    except:
        raise BizError(StatusCode.NOT_ACCOUNT)
    else:
        if record.username == 'admin':
            raise BizError(StatusCode.ADMIN_ERR)
        else:
            record.delete()

    return ApiResponse({})


# 老师相关接口
def edit_teacher(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    action = json_param.get('action', '')
    t_name = json_param.get('t_name', '')
    t_gender = json_param.get('t_gender', '')
    t_major = json_param.get('t_major', '')

    if t_name == '' or t_gender == '' or action == '' or t_major == '':
        raise BizError(StatusCode.NOT_PARAM)

    if t_gender != '1' and t_gender != '0':
        raise BizError(StatusCode.PARAM_ERR)

    try:
        Lesson.objects.get(l_name=t_major)
    except:
        raise BizError(StatusCode.NOT_LESSON)

    if action == 'add':
        record = Teacher(t_name=t_name, t_gender=t_gender, t_major=t_major)
        record.save()
    elif action == 'edit':
        t_id = json_param.get('t_id', '')
        try:
            record = Teacher.objects.get(t_id=t_id)
        except:
            raise BizError(StatusCode.NOT_TEACHER)
        else:
            record.t_name = t_name
            record.t_gender = t_gender
            record.t_major = t_major
            record.save()
    else:
        raise BizError(StatusCode.PARAM_ERR)

    return ApiResponse({})


def del_teacher(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    t_id = json_param.get('t_id', '')
    try:
        record = Teacher.objects.get(t_id=t_id)
    except:
        raise BizError(StatusCode.NOT_TEACHER)
    else:
        record.delete()
        Account.objects.filter(t_id=t_id).delete()

    return ApiResponse({})


def list_teacher(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    page_no = json_param.get('page_no', 1)
    page_size = json_param.get('page_size', 10)

    record_list = Teacher.objects.all().values('t_id', 't_name', 't_gender', 't_major',
                                               'create_time', 'edit_time').order_by('t_id')
    paginator = Paginator(record_list, page_size)

    try:
        records = [c for c in paginator.page(page_no)]
    except EmptyPage:
        records = []

    data = {
        'list': records,
        'total_page': paginator.num_pages,
        'page_no': page_no,
        'page_size': page_size
    }
    return ApiResponse(data)


def major_teacher(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    l_name = json_param.get('t_major', '')

    if l_name == '':
        raise BizError(StatusCode.NOT_PARAM)

    record_list = Teacher.objects.filter(t_major=l_name).values()

    records = []
    for i in range(len(record_list)):
        records.append(record_list[i])

    return ApiResponse(records)


# 学生相关接口
def edit_student(request):
    json_param = json.loads(request.body)
    c_name = json_param.get('c_name', '')
    s_name = json_param.get('s_name', '')
    s_code = json_param.get('s_code', '')
    s_age = json_param.get('s_age', '')
    s_gender = json_param.get('s_gender', '')
    action = json_param.get('action', '')

    if c_name == '' or s_name == '' or s_code == '' \
            or s_age == '' or s_gender == '' or action == '':
        raise BizError(StatusCode.NOT_PARAM)

    if s_gender != '1' and s_gender != '0':
        raise BizError(StatusCode.PARAM_ERR)

    try:
        Class.objects.get(c_name=c_name)
    except:
        raise BizError(StatusCode.NOT_CLASS_NAME)

    if action == 'add':
        try:
            Student.objects.get(s_code=s_code)
        except:
            record = Student(c_name=c_name, s_name=s_name, s_code=s_code, s_gender=s_gender, s_age=s_age)
            record.save()
        else:
            raise BizError(StatusCode.STUDENT_CODE_EXIST)
    elif action == 'edit':
        s_id = json_param.get('s_id', '')
        if s_id == '':
            raise BizError(StatusCode.NOT_PARAM)
        try:
            record = Student.objects.get(s_id=s_id)
        except:
            raise BizError(StatusCode.NOT_STUDENT)
        else:
            record.c_name = c_name
            record.s_name = s_name
            record.s_code = s_code
            record.s_gender = s_gender
            record.s_age = s_age
            try:
                record.save()
            except:
                raise BizError(StatusCode.STUDENT_CODE_EXIST)

    return ApiResponse({})


def del_student(request):
    json_param = json.loads(request.body)
    s_id = json_param.get('s_id', '')
    try:
        record = Student.objects.get(s_id=s_id)
    except:
        raise BizError(StatusCode.NOT_STUDENT)
    else:
        record.delete()
        Score.objects.filter(s_id=s_id).delete()

    return ApiResponse({})


def list_student(request):
    json_param = json.loads(request.body)
    page_no = json_param.get('page_no', 1)
    page_size = json_param.get('page_size', 10)

    record_list = Student.objects.all().values('s_id', 'c_name', 's_name', 's_code', 's_gender',
                                               's_age', 'create_time', 'edit_time').order_by('s_id')
    paginator = Paginator(record_list, page_size)

    try:
        records = [c for c in paginator.page(page_no)]
    except EmptyPage:
        records = []

    data = {
        'list': records,
        'total_page': paginator.num_pages,
        'page_no': page_no,
        'page_size': page_size
    }
    return ApiResponse(data)


def student_info(request):
    json_param = json.loads(request.body)
    s_code = json_param.get('s_code', '')
    try:
        student = Student.objects.values('s_id', 'c_name', 's_name', 's_code', 's_age', 's_gender').get(s_code=s_code)
    except:
        raise BizError(StatusCode.NOT_STUDENT_CODE)
    else:
        score = Score.objects.all().filter(s_id=student['s_id']).values('f_score', 'l_name')
        lesson = Lesson.objects.all().values('l_name')
        score_list = []
        f_list = []
        [f_list.append(score[j]['l_name']) for j in range(len(score))]
        [score_list.append({'l_name': k['l_name'], 'f_score': ''}) for k in lesson if k['l_name'] not in f_list]
        [score_list.append({'l_name': score[j]['l_name'], 'f_score': score[j]['f_score']}) for j in range(len(score))]
        student['score'] = score_list

        return ApiResponse(student)


# 班级相关接口
def edit_class(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    t_id = json_param.get('t_id', '')
    c_name = json_param.get('c_name', '')
    c_grade = json_param.get('c_grade', '')
    action = json_param.get('action', '')

    if t_id == '' or c_name == '' or c_grade == '' or action == '':
        raise BizError(StatusCode.NOT_PARAM)

    if len(c_grade) != 1:
        raise BizError(StatusCode.PARAM_ERR)

    if action == 'add':
        try:
            Class.objects.get(c_name=c_name)
        except:
            record = Class(t_id=t_id, c_name=c_name, c_grade=c_grade)
            record.save()
        else:
            raise BizError(StatusCode.CLASS_NAME_EXIST)
    elif action == 'edit':
        c_id = json_param.get('c_id', '')
        try:
            record = Class.objects.get(c_id=c_id)
        except:
            raise BizError(StatusCode.NOT_CLASS)
        else:
            record.t_id = t_id
            record.c_name = c_name
            record.c_grade = c_grade
            try:
                record.save()
            except:
                raise BizError(StatusCode.CLASS_NAME_EXIST)
    else:
        raise BizError(StatusCode.PARAM_ERR)

    return ApiResponse({})


def del_class(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    c_id = json_param.get('c_id', '')
    try:
        record = Class.objects.get(c_id=c_id)
    except:
        raise BizError(StatusCode.NOT_CLASS)
    else:
        record.delete()

    return ApiResponse({})


def list_class(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)

    json_param = json.loads(request.body)
    page_no = json_param.get('page_no', 1)
    page_size = json_param.get('page_size', 10)

    if int(account_dict['level']) == 0:
        record_list = Class.objects.all().values().order_by('c_id')
    else:
        record_list = Class.objects.all().filter(t_id=account_dict['t_id']).values().order_by('c_id')

    paginator = Paginator(record_list, page_size)

    for i in range(len(record_list)):
        try:
            teacher = Teacher.objects.values().get(t_id=record_list[i]['t_id'])
        except:
            record_list[i]['t_name'] = ""
        else:
            record_list[i]['t_name'] = teacher['t_name']

        del record_list[i]['t_id']
    try:
        records = [c for c in paginator.page(page_no)]
    except EmptyPage:
        records = []

    data = {
        'list': records,
        'total_page': paginator.num_pages,
        'page_no': page_no,
        'page_size': page_size
    }
    return ApiResponse(data)


# 科目相关接口
def edit_lesson(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    l_name = json_param.get('l_name', '')
    action = json_param.get('action', '')

    if l_name == '' or action == '':
        raise BizError(StatusCode.NOT_PARAM)

    if action == 'add':
        record = Lesson(l_name=l_name)
        try:
            record.save()
        except:
            raise BizError(StatusCode.LESSON_NAME_EXIST)

    elif action == 'edit':
        l_id = json_param.get('l_id', '')
        try:
            record = Lesson.objects.get(l_id=l_id)
        except:
            raise BizError(StatusCode.NOT_LESSON)
        else:
            record.l_name = l_name
            try:
                record.save()
            except:
                raise BizError(StatusCode.LESSON_NAME_EXIST)

    return ApiResponse({})


def del_lesson(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    l_id = json_param.get('l_id', '')
    try:
        record = Lesson.objects.get(l_id=l_id)
    except:
        raise BizError(StatusCode.NOT_LESSON)
    else:
        record.delete()
        Score.objects.all().filter(l_name=record.l_name).delete()

    return ApiResponse({})


def list_lesson(request):
    auth_token = request.META.get('HTTP_AUTH_TOKEN')
    account_dict = cache.get(auth_token)
    if int(account_dict['level']) != 0:
        raise BizError(StatusCode.NOT_LEVEL)

    json_param = json.loads(request.body)
    page_no = json_param.get('page_no', 1)
    page_size = json_param.get('page_size', 10)

    record_list = Lesson.objects.all().values().order_by('l_id')
    paginator = Paginator(record_list, page_size)

    try:
        records = [c for c in paginator.page(page_no)]
    except EmptyPage:
        records = []

    data = {
        'list': records,
        'total_page': paginator.num_pages,
        'page_no': page_no,
        'page_size': page_size
    }
    return ApiResponse(data)


# 分数相关接口
def edit_score(request):
    json_param = json.loads(request.body)
    s_id = json_param.get('s_id', '')
    score_list = json_param.get('score_list', '')

    print(json_param)

    if s_id == '' or score_list == '':
        raise BizError(StatusCode.NOT_PARAM)
    try:
        Student.objects.get(s_id=s_id)
    except:
        raise BizError(StatusCode.NOT_STUDENT)

    l_name = list(score_list.keys())
    f_score = list(score_list.values())
    for i in range(len(score_list)):
        try:
            Lesson.objects.get(l_name=l_name[i])
        except:
            print(l_name[i])
            raise BizError(StatusCode.NOT_LESSON_NAME)
        else:
            try:
                record = Score.objects.get(s_id=s_id, l_name=l_name[i])
            except:
                record = Score(s_id=s_id, l_name=l_name[i], f_score=f_score[i])
                try:
                    record.save()
                except:
                    raise BizError(StatusCode.LENGTH_ERR)
            else:
                record.l_name = l_name[i]
                record.f_score = f_score[i]
                try:
                    record.save()
                except:
                    raise BizError(StatusCode.LENGTH_ERR)

    return ApiResponse({})


def list_score(request):
    json_param = json.loads(request.body)
    page_no = json_param.get('page_no', 1)
    page_size = json_param.get('page_size', 10)

    record_list = Student.objects.all().values('s_id', 's_name').order_by('s_id')
    paginator = Paginator(record_list, page_size)

    lesson = Lesson.objects.all().values('l_name')
    for i in range(len(record_list)):
        score = Score.objects.all().filter(s_id=record_list[i]['s_id']).values('f_score', 'l_name', 'edit_time')
        score_list = []
        time_list = []
        f_list = []
        for j in range(len(score)):
            score_list.append({'l_name': score[j]['l_name'], 'f_score': score[j]['f_score']})
            time_list.append(score[j]['edit_time'])

        [f_list.append(score[j]['l_name']) for j in range(len(score))]
        [score_list.append({'l_name': k['l_name'], 'f_score': ''}) for k in lesson if k['l_name'] not in f_list]
        record_list[i]['edit_time'] = my_util.latest_time(time_list)
        record_list[i]['score'] = score_list
    try:
        records = [c for c in paginator.page(page_no)]
    except EmptyPage:
        records = []

    data = {
        'list': records,
        'total_page': paginator.num_pages,
        'page_no': page_no,
        'page_size': page_size
    }
    return ApiResponse(data)


# excel导入导出
def excel_upload(request):
    if request.method == 'POST':
        try:
            file = request.FILES['my_file']
        except:
            raise BizError(StatusCode.NOT_PARAM)
        else:
            suffix = file.name.split('.')[1]
            if suffix == 'xlsx' or suffix == 'xls':
                read_file = xlrd.open_workbook(filename=None, file_contents=file.read())
                sheets1 = read_file.sheets()[0]
                sheets1_rows = sheets1.nrows
                lesson = Lesson.objects.all().values('l_name')
                score_list = []
                lesson_list = []
                try:
                    for i in range(sheets1_rows):
                        row = sheets1.row_values(i)
                        if i == 0:
                            if row[0] != '学籍号':
                                return JsonResponse({'code': 5004, 'msg': '格式错误，请参考文献'})
                            [lesson_list.append(k['l_name']) for k in lesson]
                            [score_list.append(row[j]) for j in range(1, len(row)) if row[j] in lesson_list]

                        if i > 0:
                            try:
                                student = Student.objects.get(s_code=row[0])
                            except:
                                raise BizError(StatusCode.NOT_STUDENT)
                            else:
                                for j in range(1, len(score_list) + 1):
                                    try:
                                        score = Score.objects.get(s_id=student.s_id, l_name=score_list[j-1])
                                    except:
                                        Score(s_id=student.s_id, l_name=score_list[j-1], f_score=int(row[j])).save()
                                    else:
                                        score.f_score = int(row[j])

                except Exception as e:
                    print(e)
                    raise BizError(StatusCode.SYS_ERR)
    else:
        raise BizError(StatusCode.REQUEST_ERR)

    return ApiResponse({})


def excel_export(request):
    student_list = Student.objects.all().order_by('s_id')
    lesson_list = Lesson.objects.all().order_by('l_name')

    student_score = []
    for i in student_list:
        score_list = []
        lesson_name = []
        score = Score.objects.all().filter(s_id=i.s_id).order_by('l_name')
        print(score)
        score_list.append(i.s_code)
        [lesson_name.append(score[j].l_name) for j in range(len(score))]
        [score_list.append('0') for j in lesson_list if j.l_name not in lesson_name]
        [score_list.append(j.f_score) for j in score]
        student_score.append(score_list)

    # 设置HTTPResponse的类型
    response = HttpResponse(content_type='application/vnd.ms-excel')
    response['Content-Disposition'] = 'attachment;filename=score_data.xls'
    # 导出excel表
    if student_score:
        # 创建工作簿
        ws = xlwt.Workbook(encoding='utf-8')
        # 添加第一页数据表
        w = ws.add_sheet('sheet1')
        # 写入表头
        w.write(0, 0, u'学籍号')
        [w.write(0, i + 1, u'%s' % lesson_list[i].l_name) for i in range(len(lesson_list))]
        # 写入数据
        excel_row = 1
        for row in student_score:
            w.write(excel_row, 0, row[0])
            [w.write(excel_row, i, int(row[i])) for i in range(1, len(row))]
            excel_row += 1
        # 写出到IO
        output = BytesIO()
        ws.save(output)
        # 重新定位到开始
        output.seek(0)
        response.write(output.getvalue())

    return response
